#include "vsf.h"
#include "component/port/linux/vsflinux.h"

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>

#include <sys/time.h>

void *malloc(size_t size)
{
	return vsf_bufmgr_malloc(size);
}

void *realloc(void *p, size_t size)
{
//	return vsf_bufmgr_realloc(p, size);
	void *newp = malloc(size);
	if ((newp != NULL) && (p != NULL))
	{
		memcpy(newp, p, size);
		free(p);
	}
	return newp;
}

void free(void *p)
{
	if (p != NULL)
		vsf_bufmgr_free(p);
}

void *calloc(size_t n, size_t size)
{
	size_t allsize = n * size;
	void *ret = vsf_bufmgr_malloc(allsize);
	if (ret != NULL)
		memset(ret, 0, allsize);
	return ret;
}

void bzero(void *str, int size)
{
	memset(str, 0, size);
}

char *strdup(const char *str)
{
	char *newstr = vsf_bufmgr_malloc(strlen(str) + 1);
	return strcpy(newstr, str);
}

int fputs(const char *str, FILE *stream)
{
	return ((stream == stdout) || (stream == stderr)) ?
			vsfdbg_prints((char *)str) : 0;
}

int printf(const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	vsfdbg_printf_arg(format, &ap);
	va_end(ap);
	return 0;
}

int fprintf(FILE *file, const char *format, ...)
{
	if ((file == stdout) || (file == stderr))
	{
		va_list ap;
		va_start(ap, format);
		vsfdbg_printf_arg(format, &ap);
		va_end(ap);
	}
	return 0;
}

time_t time(time_t *__timer)
{
	struct timeval tv;
	time_t t;

	gettimeofday(&tv, NULL);
	t = tv.tv_sec + tv.tv_usec / 1000000;
	if (__timer != NULL)
		*__timer = t;
	return t;
}

static inline unsigned long mktime_do(unsigned int year, unsigned int mon,
	unsigned int day, unsigned int hour, unsigned int min, unsigned int sec)
{
	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
		mon += 12;					/* Puts Feb last since it has leap day */
		year -= 1;
	}

	return (((
				(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
				year*365 - 719499
			)*24 + hour /* now have hours */
		)*60 + min /* now have minutes */
	)*60 + sec; /* finally seconds */
}

time_t mktime(struct tm * timeptr)
{
	return (time_t)mktime_do(timeptr->tm_year, timeptr->tm_mon,
		timeptr->tm_yday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
}

size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr)
{
	*str = '\0';
	return 0;
}

// libgen
#include <libgen.h>
char *basename(char *path)
{
	char *ext, *tmp;

	ext = tmp = path;
	while (1)
	{
		tmp = strchr(ext, '/');
		if (tmp != NULL)
			ext = tmp + 1;
		else
			break;
	}
	return ext;
}

// stdio
static int vsflinux_stdio_fcntl(struct vsflinux_fd_t *sfd, int cmd, long arg)
{
	return 0;
}

static ssize_t vsflinux_stdio_read(struct vsflinux_fd_t *sfd, void *buf, size_t count)
{
	return 0;
}

static ssize_t vsflinux_stdio_write(struct vsflinux_fd_t *sfd, const void *buf, size_t count)
{
	vsfdbg_printr(buf, count);
	return 0;
}

static int vsflinux_stdio_close(struct vsflinux_fd_t *sfd)
{
	return 0;
}

struct vsflinux_fdop_t vsflinux_stdio_fdop =
{
	.fcntl = vsflinux_stdio_fcntl,
	.read = vsflinux_stdio_read,
	.write = vsflinux_stdio_write,
	.close = vsflinux_stdio_close,
};

int vsflinux_libc_init(void)
{
	struct vsflinux_fd_t *sfd;

	int fd = vsflinux_fd_new(&sfd, 0, &vsflinux_stdio_fdop);
	if (fd != 0) return VSFERR_FAIL;
	// init stdin
	sfd->flags |= O_RDONLY;

	fd = vsflinux_fd_new(&sfd, 0, &vsflinux_stdio_fdop);
	if (fd != 1) return VSFERR_FAIL;
	// init stdout
	sfd->flags |= O_WRONLY;

	fd = vsflinux_fd_new(&sfd, 0, &vsflinux_stdio_fdop);
	if (fd != 2) return VSFERR_FAIL;
	// init stderr
	sfd->flags |= O_WRONLY;

	return 0;
}
